perm filename TCPRA.MAC[IP,SYS] blob
sn#680229 filedate 1982-10-14 generic text, type T, neo UTF8
;CWL:<403-TCP>TCPRA.MAC.40303 6-May-82 16:49:08, Edit by CLYNN
; Fix transmitter exceeding window leading to negative window bug
; Pass time to EMTPKT, work on UPDWND/NUWNDO
;<403-TCP>TCPRA.MAC.40301 29-Jan-82 15:07:48, Edit by CLYNN
; Updated for TCP release 3
;[BBND]<401-TCP>TCPRA.MAC.96, 11-Aug-81 13:23:00, Ed: CLYNN
; Fix: internet fork loop due to full tvt input buffer at REAS20
;[BBNF]<401-TCP>TCPRA.MAC.95, 10-Jul-81 15:33:00, Ed: CLYNN
; Fix: TVTL zero because closing problems in REASEM to 16 & NUWNDO
; FIN with URG in REAS16, No room in RAINI
SEARCH INPAR,TCPPAR,PROLOG
TTITLE TCPRA
SUBTTL TCP Reasembler, William W. Plummer, 19JAN77
SWAPCD
COMMENT !
The REASEMBLER is called with TCB set up to point at a
(locked) connection block. Its function is to transfer
data from packets queued for it by the Inputprocessor
into user buffers queued by RECV calls on the TCP.
The REASEMBLER also processes certain control bits
in the packets such FIN. Once handled,
the PACKETIZER is signaled so that it may generate an
ACK for the packet. TCP Virtual Terminal
characters are moved into line buffers via the
TELNET protocol routines in the NVT code.
* REASEM ... 3 ...... Fill user RECV buffers from packets received
PRCEOL ... 10 ...... Process EOL
PRCFIN ... 10 ...... Process FIN
PRCDAT ... 11 ...... Process data
* NUWNDO ... 12 ...... Update receive window after packet processed or RECV
* FLSRBF ... 14 ...... Flush receive buffers
* RAINI .... 15 ...... Initialize RA process block
!
; Reasembler
;TCB/ (Extended) Pointer to connection block
;
; CALL REASEM
;Ret+1: always
REASEM::LOCAL <BYTNUM,XFRCNT,RCVLFT,LINBLK>
PUSH P,PKT
PUSH P,TPKT
PUSH P,BFR
SETO LINBLK, ; Indicate no terminal line locked
; <0 must check TTVT, not locked
; (NOTSYN or no TVT assigned)
; =0 non-standard, locked
; >0 have TTVT (& TVTL & R-SYNCED) & locked
JE TTVT,(TCB),REASMN ; Jump if not a TCP Virtual Terminal
LOAD T1,TRSYN,(TCB) ; State of receive side
CAIE T1,SYNCED ; OK to pass data now?
JRST REASMN ; No. But process control
LOAD T2,TVTL,(TCB) ; Get the line number
JUMPE T2,REASMN ; Jump if none assigned yet or gone away
CALL TVTCHK ; Lock the terminal data base
JRST [JUMPLE T2,REASMN ;Nothing locked (inactive, becoming active)
SETZ T2, ; Locked & non-standared so
JRST .+1] ; must update LINBLK
MOVEM T2,LINBLK ; Save here for later
REASMN:
; Top of main loop:
; Check the queue of packets from the InputProcessor. If there are
; no packets, there is nothing that the Reassembler can do.
REASM0: LOAD PKT,QNEXT,<+TCBRPQ(TCB)> ; Get pointer to first thing on Q
CAIN PKT,TCBRPQ(TCB) ; Receive packet queue empty?
JRST REASMX ; Yes. Get out.
SETSEC PKT,INTSEC ; Make extended address
LOAD T1,PIDO,(PKT) ; Internet data offset in words
XMOVEI TPKT,PKTELI(PKT) ; Pointer to Internet portion of packet
ADD TPKT,T1 ; Pointer to TCP portion of packet
; Set BFR to 0 if this is a TVT so as to avoid code which
; fiddles with normal buffers.
JE TTVT,(TCB),REAS0A ; If not TVT go get BFR
MOVX BFR,0 ; Indicate no normal buffer
SKIPG T2,LINBLK ; Set arg.
JRST REAS0A ; Not a TVT or gone away
CALL TVTISP ; Get space in input buffer
JFCL ;JUMPN T1,REASM3 ; Continue if there is some
JFCL ;JN TRPP,(TCB),REASMX ; Get out if part. pkt and no space
JRST REASM3 ; Forge ahead to (say) open conn/closing
REAS0A:
; Try to find a user buffer for filling. This could be the Receive
; current buffer left from a previous pass or one queued from
; a user RECV call.
LOAD BFR,TRCB,(TCB) ; Get 0 or receive current buffer
SETSEC BFR,INTSEC ; Make extended address
TRNE BFR,-1 ; Is there a current buffer?
JRST REASM3 ; Go use what is left of it
LOAD BFR,QNEXT,<+TCBRBQ(TCB)> ; Pointer to first buffer queued
CAIE BFR,TCBRBQ(TCB) ; Empty if that is the queue head
JRST REASM1 ; Go dequeue the buffer and use it
; No buffer available. If there is a partially processed packet,
; we can do no more. Otherwise there may be controls (SYN)
; which can be handled. This allows a SYN to be ACKd and thus a
; connection to open before any user RECVs have been done.
JN TRPP,(TCB),REASMX ; Get out if there is a partial packet
MOVX BFR,0 ; Indicate no buffer to use.
JRST REASM3 ; Proceed
; Dequeue buffer at the head of the receive buffer queue
REASM1: SETSEC BFR,INTSEC ; Make extended address
MOVE T1,BFR ; Pointer to the buffer
CALL DQ ; Dequeue it
STOR BFR,TRCB,(TCB) ; And remember as the current buffer
REASM3: LOAD RCVLFT,TRLFT,(TCB)
JE TRPP,(TCB),REASM4 ; Jump if not continuing a packet
LOAD BYTNUM,TRCBY,(TCB) ; Where to resume in this packet
JRST REAS13 ; Go process the remainder
; First time we have seen this packet. Flush it unless there is
; some unseen stuff in it.
REASM4: AOS RAPKCT ; Count packets seen by Reassembler
MOVX T1,PT%TRA
TDNE T1,INTTRC ; Want trace?
CALL PRNPKT ; Yes
MOVE T1,RCVLFT ; Recv Left -- start of "The present"
LOAD T2,TRWND,(TCB) ; Get current window width
ADD T2,T1 ; Form Recv.Right -- beginning of "Past"
ADDI T2,1 ; Allow SYN thru 0-window crock
MODSEQ T2 ; T1,T2 are Left and Right of the past
LOAD T3,PSEQ,(TPKT) ; Sequence of the packet
LOAD T4,PESEQ,(PKT) ; Get end + 1 from packet
CALL OVRLAP ; Packet included in the past?
JUMPN T1,REASM5 ; Jump if not.
MOVEI T1,RADLAY ; Select Reassembler delay histogram
SKIPE STATF ; Actually taking statistics?
CALL TSTAMP ; Yes. Process the timestamp.
MOVX T1,PT%XX4 ; Code for reassembler
TDNE T1,INTTRC ; Want trace?
CALL PRNPKT ; Yes, Call the packet printer
MOVE T1,PKT ; Pointer to this useless packet
CALL DQ ; Dequeue it
CALL RETPKT ; Give space to freestorage
JRST REASM0 ; Try the next packet.
REASM5:
; If Left is within the current packet, there is something which
; can be reassembled out of it.
LOAD T1,PSEQ,(TPKT) ; Start of the packet
MOVE T2,RCVLFT ; Next thing needed for reassembly
LOAD T3,PESEQ,(PKT) ; End of the packet
CALL CHKWND ; Left within the packet?
JUMPE T1,REASMX ; Jump if not. Must wait for it to show
; Setup BYTNUM to be the byte number within the packet where data
; handling should start.
LOAD RCVLFT,TRLFT,(TCB) ; Get updated copy
;REAS10:
MOVE BYTNUM,RCVLFT ; Next to be reassembled
LOAD T1,PSEQ,(TPKT) ; Start of packet
SUB BYTNUM,T1 ; Offset into data
JUMPLE BYTNUM,REAS12 ; No control to worry about
LOAD T1,PSYN,(TPKT) ; Get value of SYN bit
SUBI BYTNUM,0(1) ; Discount space taken by SYN
REAS12:
; Setup XFRCNT to be the number of bytes to transfer out of the
; packet into the user buffer.
REAS13: LOAD XFRCNT,PIPL,(PKT) ; Get total length
LOAD T1,PIDO,(PKT) ; Number of words in Internet header
LOAD T2,PTDO,(TPKT) ; Number of words in TCP header
ADD T1,T2 ; Number of header words
ASH T1,2 ; Number of header bytes
SUB XFRCNT,T1 ; Number of TCP data bytes
SUB XFRCNT,BYTNUM ; Forget already processed bytes
PUSH P,XFRCNT ; Save packet count (number available)
SKIPG T2,LINBLK ; Is this a TVT w/ standard data block?
TDZA T1,T1 ; No. Assume no buf and no space
CALL TVTISP ; Yes. Get amount of space to T1
JUMPE BFR,REAS14 ; Jump if no buffer
LOAD T1,BCNT,(BFR) ; Get number of holes in the buffer
REAS14:
CAMLE XFRCNT,T1 ; Min of available bytes and space
MOVE XFRCNT,T1 ; is the actual transfer count
JUMPLE XFRCNT,REAS15 ; Jump if nothing to transfer.
ADDM XFRCNT,BYTRCT ; Count bytes received
MOVE T1,BYTNUM ; Where to start transfer from packet
LOAD T3,PTDO,(TPKT) ; Get TCP data offset in words
IDIVI T1,4 ; Get words and byte into data
ADD T1,T3 ; Get word offset from TPKT
HLL T1,[POINT 8,.-.(TPKT),-1
POINT 8,.-.(TPKT),07
POINT 8,.-.(TPKT),15
POINT 8,.-.(TPKT),23](T2)
SKIPG T2,LINBLK ; Addr of dynamic data area
JRST REA14A ; None
MOVE T3,XFRCNT ; How much to transfer
CALL PRCTVT ; Process TVT chr on line in T2
JRST REAS15
REA14A:
MOVE T2,XFRCNT ; How much to transfer
CALL PRCDAT ; Process the data
REAS15: POP P,T1 ; Restore the packet count
; If the packet has been emptied into a buffer after the connection
; has become synchronized in the receive direction, process the
; trailing controls and flush the packet. If the buffer was
; filled, report the fact to the user.
LOAD T2,TRSYN,(TCB) ; Get receive state
CAIE T2,SYNCED ; Synchronized?
CAIN T2,FINRCV ; or FIN Received?
CAIA ; Yes.
JRST REAS19 ; No. Save as partial packet.
; ?? See if user buffer is full here for USRBFF a la reas18
CAME T1,XFRCNT ; Emptied all data from the packet?
JRST REAS18 ; No.
JN TTVT,(TCB),REAS16 ; Assume EOL and buffer if TVT
JUMPN BFR,REAS16 ; Into a buffer?
JN PEOL,(TPKT),REAS18 ; Lack buffer to report EOL in
REAS16:
; Packet empty, finish it off & loop back for next
SETZRO TRPP,(TCB) ; Indicate no partial packet waiting
; See if we can leave receive urgent mode. The urgent pointer must
; coincide with the end of a packet plus one. So, we need only test the
; PESEQ for equality with the urgent pointer to tell if data up to the
; urgent pointer has been given to the user.
JE TRURG,(TCB),REAS17 ; Forget if not in receive urgent mode
LOAD T1,PESEQ,(TPKT) ; Get the end plus one of this packet
LOAD T2,TRURP,(TCB) ; And the receive urgent pointer
CAMGE T1,T2 ; Will the urgent pointer be acked? (FIN)
JRST REAS17 ; No.
SETZRO TRURG,(TCB) ; Leave receive urgent mode
REAS17:
JN TTVT,(TCB),REA17A ; No EOL processing on TVTs
JE PEOL,(TPKT),REA17A
CALL PRCEOL ; Process EOL
REA17A:
JE PFIN,(TPKT),REA17B
CALL PRCFIN ; Process FIN if present, generate ack
REA17B:
LOAD T1,PESEQ,(PKT) ; Get the sequence number following Pkt
STOR T1,TRLFT,(TCB) ; Set the new Left
CALL NUWNDO ; Update the window, maybe generate ACK
MOVEI T1,RADLAY ; Select Reassembler delay
SKIPE STATF ; Taking statistics right now?
CALL TSTAMP ; Yes, process the timestamp
MOVX T1,PT%XX4 ; "Reassembled" code
TDNE T1,INTTRC ; Want trace?
CALL PRNPKT ; Yes, Print the packet
MOVX T1,PT%TDR
TDNE T1,INTTRC ; Want trace?
CALL PRNPKT ; Yes
; Since we have completely finished with this packet, dequeue it
; and return the space to free storage.
MOVE T1,PKT ; Pointer to the packet
CALL DQ ; Dequeue it
CALL RETPKT ; Free the area
JRST REASM0 ; And process the next packet.
; Here when more remains in packet
REAS18: JUMPE BFR,REAS19 ; Jump if no buffer
JN BCNT,(BFR),REAS19 ; Jump if buffer not filled
MOVX T1,OK ; Indicate buffer is good
CALL USRBFF ; User buffer filled routine
SETZRO TRCB,(TCB) ; Indicate no current buffer anymore
REAS19:
; Save the partial packet for the next time through.
SETONE TRPP,(TCB) ; Set the partial packet waiting bit
MOVE T1,XFRCNT ; Number transferred
ADD T1,BYTNUM ; Where the transfer started
STOR T1,TRCBY,(TCB) ; Is where to resume in the packet
JUMPN BYTNUM,REAS20 ; First time we have
JE PSYN,(TPKT),REAS20 ; Seen a packet with a SYN in it?
ADD RCVLFT,XFRCNT ; Yes. Update Left
STOR RCVLFT,TRLFT,(TCB)
MOVX T1,↑D500
CALL ENCPKT ;FRCPKT ; Get it ACK'd
REAS20:
JUMPE BFR,REASMX ; If TVT input full, stop now
JE TRCB,(TCB),REASM0 ; Try to get another buffer from queue
REASMX: SKIPL T2,LINBLK ; Do we have a term line locked?
CALL ULKTTY ; Yes. Unlock it
POP P,BFR
POP P,TPKT
POP P,PKT
RESTORE
RET
; Process EOL
;TCB/ (Extended) Locked connection block
;BFR/ (Extended) Current buffer
;
; CALL PRCEOL
;Ret+1: always
PRCEOL: MOVX T1,<<OK>B7+TCP%EL> ; OK code, with end of letter flag
CALL USRBFF ; Tell user buffer filled
MOVX BFR,0 ; Indicate no current buffer
STOR BFR,TRCB,(TCB)
RET
; Process FIN
;TCB/ (Extended) Locked connection block
;
; CALL PRCFIN
;Ret+1: always
PRCFIN: MOVX T1,FINRCV ; FIN Received state
STOR T1,TRSYN,(TCB) ; Set into TCB
AOS FINRCT ; Count FINs received
MOVX T1,↑D100
CALL ENCPKT ; Make sure its ACKed promptly
RET
; Process data from packet
;TCB/ (Extended) Locked connection block
;PKT/ (Extended) Packet
;TPKT/ (Extended) pointer to TCP part of packet
;BFR/ (Extended) Buffer
;T1/ Byte pointer into packet
;T2/ Count of bytes to transfer to buffer
;
; CALL PRCDAT
;Ret+1: always
PRCDAT: LOCAL <PKTPTR,XFRCNT>
DMOVEM T1,PKTPTR
;PRCDA1:
CALL SETTUM ; Set TCP's usermode map
MOVE T1,PKTPTR ; Source byte pointer
LOAD T2,BPTR,(BFR) ; Destination byte pointer
MOVE T3,XFRCNT ; Number to do
SETZ T4, ; Monitor-to-user transfer
CALL XFRDAT ; Do the data transfer
STOR T2,BPTR,(BFR) ; Store back updated pointers
MOVEM T1,PKTPTR
;PRCDA4:
LOAD T1,BCNT,(BFR) ; Get number of holes in buffer at start
SUB T1,XFRCNT ; Reduce by number transferred
STOR T1,BCNT,(BFR) ; Update the count in the buffer
LOAD T3,TRBS,(TCB) ; Get receive bufferspace (due to RECVs)
SUB T3,XFRCNT ; Remove space just filled from window
STOR T3,TRBS,(TCB)
;;;; CALL USRBUD ; Update the user's buffer header
CALL USTTUM
PRCDAX: RESTORE
RET
; Update Receive Window
; Whenever a user RECV increases the available buffer space or
; after processing a packet entirely the size of the window being
; sent to the remote TCP is determined and set into the TCB. If
; processing the packet has moved Received Left, the Packetizer is
; signaled so it will generate an ACK.
;TCB/ (Extended) Locked Connection block
; CALL NUWNDO
;Ret+1: always
NUWNDO::LOAD T1,TRBS,(TCB) ; Currently available buffer space
JE TTVT,(TCB),NUWND1 ; If a TVT
SETZ T1, ; Assume no space
LOAD T2,TVTL,(TCB) ; Unless a line
JUMPE T2,NUWND1 ; Has been assigned
CALL STADYN ; Get line's data block
JRST NUWND1 ; ?? address
CALL TVTISP ; Get TTY input space
NUWND1:
; Now have available input space, maybe zero
LOAD T2,TRLWN,(TCB) ; Seq # of last receive-right reported
JUMPL T2,NUWND5 ; Not yet available, use actual space
LOAD T3,TRLFT,(TCB) ; Compute unused space from last window
SUB T2,T3
MODSEQ T2
CAIL T2,<.RTJST(-1,PIPL)> ;CAML T2,[MAXSEQ/2] ; Beware negative
SETZ T2, ; Window (transmitter sent too much)
JUMPLE T1,NUWND4 ; No space, don't increase offered window
; (but don't shrink it either)
MOVE T4,INTXPB ; Estimated packet size
SUBI T4,MINIHS+MINTHS ; w/o minimal headers
JFCL ; LSH T4,1 ; How optimistic are we??
CAIG T1,(T4) ; If user space is less
MOVE T1,T4 ; Be optimistic
CAILE T1,<.RTJST(-1,PIPL)> ; But not more so than
MOVE T1,<.RTJST(-1,PIPL)> ; Size of window field
MOVE T3,T2 ; Remaining space, last window
LSH T3,1 ; Factor is 1/2
CAMLE T3,T1 ; If remaining .gt. 1/2 actual
NUWND4: MOVE T1,T2 ; Don't report it (no silly windows)
NUWND5: STOR T1,TRWND,(TCB) ; Offered window space
; Check if sender should be notified of ACKed data or new window info
LOAD T3,TRSYN,(TCB) ; Check connection state
LOAD T4,TSSYN,(TCB)
CAIE T4,SYNABL ; If send side doesn't have a seq #
CAIN T3,SYNABL ; or don't know foreign address
RET ; Cannot send a packet
LOAD T4,TRLFT,(TCB) ; Current ACK point
LOAD T3,TRLAK,(TCB) ; Last reported ACK point
SUB T2,T1 ; Non-zero if new window info
; LOAD T1,TSMRT,(TCB) ; (or TMNRT) ; Estimated time
; LSH T1,1 ; Pause factor
MOVX T1,↑D250 ; Estimated time too long, get RXs
CAMN T3,T4 ; If new ACK point or
SKIPE T2 ; New window space
CALL ENCPKT ; Get a packet sent in a bit
RET
; Flush Receive Buffers Called when aborting a connection
;TCB/ (Extended) Locked connection block
;T1/ Code (377B7) to be left in the buffer header for user to see
; XLP+12. EFP+7. ELP+7. ELP+14. E?T+? (TVTs)
;
; CALL FLSRBF
;Ret+1: always
FLSRBF::LOCAL <CODE>
PUSH P,BFR
MOVEM T1,CODE
LOAD BFR,TRCB,(TCB) ; Get the current receive buffer if any
SETZRO TRCB,(TCB) ; Forget there is one
JUMPE BFR,FLSRB2 ; Jump if no current buffer
SETSEC BFR,INTSEC ; Make extended address
FLSRB1: MOVE T1,CODE
LSH T1,↑D<36-8> ; Put into postion
CALL USRBFF ; Indicate user buffer "filled"
FLSRB2: LOAD BFR,QNEXT,<+TCBRBQ(TCB)> ; First thing on queue
CAIN BFR,TCBRBQ(TCB) ; If that is the head, queue now empty
JRST FLSRBX
SETSEC BFR,INTSEC ; Make extended address
MOVE T1,BFR
CALL DQ ; Dequeue the buffer
JRST FLSRB1
FLSRBX: POP P,BFR
RESTORE
RET
; RAINI Initialize RA process block
; CALL RAINI
;Ret+1: Always, T1 zero if error
RAINI:: LOCAL <PRC>
MOVEI PRC,RA ; Pointer to the Process block for RA
MOVX T1,QSZ ; Size of a queue head
CALL GETBLK ; Head must be in same section as items
JUMPE T1,RAINIX ; No room
MOVEM T1,PRCQ(PRC) ; Input queue
CALL INITQ ; Initialize it
XMOVEI T1,PRCLCK(PRC) ; Lock
CALL CLRLCK ; Initilize it
XMOVEI T1,REASEM ; The Reassembler function
MOVEM T1,PRCROU(PRC) ; Routine address
SETOM PRCWAK(PRC) ; No run time yet
MOVE T1,[<GIW TCBQRA,TCB>]; Offset of RA queue in TCB
MOVEM T1,PRCQOF(PRC) ; Store process block
MOVE T1,[<GIW TCBTRA,TCB>]; Offset of RA run time in TCB
MOVEM T1,PRCWOF(PRC) ; Store in process block
HRLOI T1,377777 ; Infinity
MOVEM T1,PRCSGT(PRC) ; Set time of most recent signal
MOVEI T1,RARNCT ; Pointer to run counter
MOVEM T1,PRCRNC(PRC) ; Put in standard place
MOVEI T1,RAUSE ; Pointer to CPU use meter
MOVEM T1,PRCTMR(PRC) ; Put in standard place
; SETO T1,
RAINIX: RESTORE
RET
TNXEND
END